package com.finance.util.export;

import lombok.Data;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.xssf.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by ljg on 2017/4/10.
 */
@Data
public class ExportBuilder<From,To> {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    private final static String DEFAULT_SHEET_NAME = "sheet";
    private final static String DEFAULT_FILENAME = "export.xlsx";
    private String fileName = DEFAULT_FILENAME;
    private String sheetName = DEFAULT_SHEET_NAME;
    private List<String> errList;
    private List<String> headNames = new ArrayList<String>();
    private Map<String,Short> headFontStyles = new HashMap<String, Short>();

    private List<String> fieldNames = new ArrayList<String>();
    private XSSFWorkbook wb;
    private XSSFSheet sheet;
    private XSSFRow row;
    private ExportBeanParse<From,To> parse;
    public ExportBuilder(Class<To> tClass,ExportBeanParse<From,To>parse) {
        this.parse = parse;
        Field[] fields = tClass.getDeclaredFields();
        for (Field field : fields){
            ExcelHead excelHead = field.getAnnotation(ExcelHead.class);
            if(excelHead != null){
                headNames.add(excelHead.name());
                headFontStyles.put(excelHead.name(),excelHead.mustImport() ? HSSFColor.RED.index:HSSFColor.BLACK.index);
                fieldNames.add(field.getName());
            }
        }
    }

    public void init(){
        // 第一步，创建一个webbook，对应一个Excel文件
        wb = new XSSFWorkbook();
        // 第二步，在webbook中添加一个sheet,对应Excel文件中的sheet
        sheet = wb.createSheet(sheetName);
        // 第三步，在sheet中添加表头第0行,注意老版本poi对Excel的行数列数有限制short
        row = sheet.createRow(0);
        //设置行
        fillHeadRow();
    }

    private String getValueByName(To t,String fieldName){
        Object ret = null;
        fieldName = fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
        Method method = null;
        try {
            method = t.getClass().getDeclaredMethod("get" + fieldName);
            ret = method.invoke(t);
            fieldName = fieldName.substring(0,1).toLowerCase()+fieldName.substring(1);
            if(t != null && Date.class.equals(t.getClass().getDeclaredField(fieldName).getType())) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                ret = sdf.format(ret);
            }
        } catch (NoSuchMethodException e) {
            logger.error("getValueByName NoSuch, ", e);
        } catch (InvocationTargetException e) {
            logger.error("getValueByName Invocation, ", e);
        } catch (IllegalAccessException e) {
            logger.error("getValueByName IllegalAccess, ", e);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        return ret == null?null:ret.toString();
    }

    private void fillHeadRow() {
        XSSFCell cell = null;
        for (int i=0;i< headNames.size();i++){
            cell = row.createCell(i);
            cell.setCellValue(headNames.get(i));
            XSSFCellStyle style = wb.createCellStyle();
            // 第四步，创建单元格，并设置值表头 设置表头居中
            style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式
            style.setWrapText(true);
            XSSFFont hssfFont = wb.createFont();
            hssfFont.setColor(headFontStyles.get(headNames.get(i)));
            style.setFont(hssfFont);
            cell.setCellStyle(style);
        }
    }

    public void fillDataList(List<From> dataList) {
        for (int i = 0; i < dataList.size(); i++){
            row = sheet.createRow(i + 1);
            From t = dataList.get(i);
            To to = parse.parse(t);
            for (int j=0;j< fieldNames.size();j++){
                row.createCell(j).setCellValue(getValueByName(to,fieldNames.get(j)));
            }
            if(this.errList != null && this.errList.size()==dataList.size()){
                XSSFCell cell = row.createCell(fieldNames.size());
                cell.setCellValue(this.errList.get(i));

                XSSFCellStyle style = wb.createCellStyle();
                style.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 创建一个居中格式
                style.setWrapText(true);
                XSSFFont hssfFont = wb.createFont();
                hssfFont.setColor(Font.COLOR_RED);
                style.setFont(hssfFont);
                cell.setCellStyle(style);
            }
        }
    }

    public void fillErrList(List<String> errList) {
        this.errList = errList;
    }

    public void out(HttpServletResponse response){
        OutputStream out = null;
        try{
            response.setHeader("content-disposition", "attachment;filename="+fileName);
            out = response.getOutputStream();
            wb.write(out);
        }catch (Exception e) {
            logger.error(e.getMessage(),e);
        }finally {
            if(out != null){
                try {
                    out.close();
                } catch (IOException e) {
                    logger.error(e.getMessage(),e);
                }
            }
        }
    }

    public void out(File file){
        FileOutputStream fout = null;
        try{
            fout = new FileOutputStream(file);
            wb.write(fout);
        }catch (Exception e) {
            logger.error(e.getMessage(),e);
        }finally {
            if(fout != null){
                try {
                    fout.close();
                } catch (IOException e) {
                    logger.error(e.getMessage(),e);
                }
            }
        }
    }

}
